import random

from web import models
from django import forms
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from web import models
from django.conf import settings
from utils.tencent.sms import send_sms_single
from utils import encrypt
from django_redis import get_redis_connection

"""注册的表单"""


class RegisterModelForm(forms.ModelForm):
    # 通过modelform覆盖原来的字段，生成页面基本的字段
    username = forms.CharField(label="用户名",
                               widget=forms.TextInput(attrs={"class": 'form-control', 'placeholder': '请输入用户名'}))
    email = forms.EmailField(label="邮箱",
                             widget=forms.TextInput(attrs={"class": 'form-control', 'placeholder': '请输入邮箱'}))
    mobile_phone = forms.CharField(label="手机号", validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机格式错误'), ],
                                   widget=forms.TextInput(attrs={"class": 'form-control', 'placeholder': '请输入验证码'}))
    password = forms.CharField(label="密码",
                               min_length=8,
                               max_length=64,
                               error_messages={
                                   'min_length': '密码长度不能小于8个字符',
                                   'max_length': '密码长度不能大于64个字符'
                               },

                               widget=forms.PasswordInput(attrs={"class": 'form-control', 'placeholder': '请输入密码'}))
    confirm_password = forms.CharField(label="重复密码", widget=forms.PasswordInput(
        attrs={"class": 'form-control', 'placeholder': '请再次输入密码'}))
    code = forms.CharField(label="验证码",
                           widget=forms.TextInput(attrs={"class": 'form-control', 'placeholder': '请输入验证码'}))
    regist_code = forms.CharField(label="内部注册码",
                                  widget=forms.TextInput(attrs={"class": 'form-control', 'placeholder': '请输入验证码'}))

    class Meta:
        model = models.UserInfo
        # 优先展示form中的字段，接着才展示modelform剩下的字段
        # fields = "__all__"
        # 重新定义页面中展示的顺序
        fields = ['username', 'email', 'password', 'confirm_password', 'mobile_phone', 'code']

    def clean_username(self):
        username = self.cleaned_data[
            'username']  # 获取的是已验证或正在验证的字段的值，验证顺序为fields = ['username', 'email', 'password', 'confirm_password', 'mobile_phone', 'code']
        exists = models.UserInfo.objects.filter(username=username).exists()
        if exists:
            self.add_error(
                ('username', '用户名已存在'))  # 此处不能用raise ValidationError，否则下面的代码都读取不到self.cleaned_data['username']

        return username

    def clean_email(self):
        email = self.cleaned_data['email']
        exists = models.UserInfo.objects.filter(email=email).exists()
        if exists:
            raise ValidationError('邮箱已存在')

        return email

    def clean_password(self):
        pwd = self.cleaned_data['password']
        # 加密密码
        pwd = encrypt.md5(pwd)
        return pwd

    def clean_confirm_password(self):
        pwd = self.cleaned_data.get('password')
        conform_pwd = self.cleaned_data['confirm_password']
        conform_pwd = encrypt.md5(conform_pwd)
        if pwd != conform_pwd:
            raise ValidationError('两次密码不一致')

        return conform_pwd

    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data['mobile_phone']

        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exists:
            raise ValidationError('手机号已注册')

        return mobile_phone

    def clean_code(self):
        code = self.cleaned_data['code']
        mobile_phone = self.cleaned_data['mobile_phone']

        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)
        if not redis_code:
            raise ValidationError('验证码失效或未发送，请重新发送')

        redis_str_code = redis_code.decode('utf-8')

        if redis_str_code != code.strip():
            raise ValidationError('验证码错误，请重新输入')
        return code

    def clean_regist_code(self):
        regist_code = self.cleaned_data['regist_code']
        if regist_code not in settings.REGIST_CODE:
            raise ValidationError('内部注册码错误，请重新输入')
        return regist_code


"""短信登录的表单"""


class LoginSmsForm(forms.Form):
    mobile_phone = forms.CharField(label="手机号", validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机格式错误'), ],
                                   widget=forms.TextInput(attrs={"class": 'form-control', 'placeholder': '请输入验证码'}))
    code = forms.CharField(label="验证码",
                           widget=forms.TextInput(attrs={"class": 'form-control', 'placeholder': '请输入验证码'}))

    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data['mobile_phone']
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if not exists:
            raise ValidationError('手机号不存在')
        return mobile_phone

    def clean_code(self):
        code = self.cleaned_data['code']
        mobile_phone = self.cleaned_data.get('mobile_phone')

        # 手机号不存在，则验证码无需在校验
        if not mobile_phone:
            return code

        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)
        if not redis_code:
            raise ValidationError('校验码失效或未发送。请重新发送')

        redis_str_code = redis_code.decode('utf-8')

        if code.strip() != redis_str_code:
            raise ValidationError('验证码错误')
        return code


"""发送短信的表单"""


class SendSmsForm(forms.Form):
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_mobile_phone(self):
        """ 手机号校验的钩子 """
        mobile_phone = self.cleaned_data['mobile_phone']

        # 判断短信模板是否有问题
        tpl = self.request.GET.get('tpl')
        template_id = settings.TENCENT_SMS_TEMPLATE.get(tpl)
        if not template_id:
            # self.add_error('mobile_phone','短信模板错误')
            raise ValidationError('短信模板错误')

        # 根据登录和注册两种情况做不同的处理
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if tpl == 'login':
            if not exists:
                raise ValidationError('手机号不存在')
        else:
            # 校验数据库中是否已有手机号
            if exists:
                raise ValidationError('手机号已存在')

        code = random.randrange(1000, 9999)

        # 发送短信
        sms = send_sms_single(mobile_phone, template_id, [code, ])
        if sms['result'] != 0:
            raise ValidationError("短信发送失败，{}".format(sms['errmsg']))

        # 验证码 写入redis（django-redis）
        conn = get_redis_connection()
        conn.set(mobile_phone, code, ex=60)

        return mobile_phone


"""用户密码登录的表单"""


class LoginForm(forms.Form):
    username = forms.CharField(label='邮箱或手机号',
                               widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入用户名'}))
    password = forms.CharField(label="密码",
                               min_length=8,
                               max_length=64,
                               error_messages={
                                   'min_length': '密码长度不能小于8个字符',
                                   'max_length': '密码长度不能大于64个字符'
                               },
                               widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': '请输入密码'}))
    code = forms.CharField(label='图片验证码',
                           widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入图片验证码'}))

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_password(self):
        pwd = self.cleaned_data['password']
        # 加密密码
        pwd = encrypt.md5(pwd)
        return pwd

    def clean_code(self):
        """检验验证码是否正确"""
        code = self.cleaned_data['code']
        session_image_code = self.request.session.get('image_code')

        if not session_image_code:
            raise ValidationError('验证码已过期！请重新输入')

        if code.strip().upper() != session_image_code.strip().upper():
            raise ValidationError('验证码错误')

        return code


"""重置密码"""


class ResetModelForm(forms.ModelForm):
    # 通过modelform覆盖原来的字段，生成页面基本的字段
    mobile_phone = forms.CharField(label="手机号", validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机格式错误'), ],
                                   widget=forms.TextInput(attrs={"class": 'form-control', 'placeholder': '请输入验证码'}))
    password = forms.CharField(label="重置密码",
                               min_length=8,
                               max_length=64,
                               error_messages={
                                   'min_length': '密码长度不能小于8个字符',
                                   'max_length': '密码长度不能大于64个字符'
                               },

                               widget=forms.PasswordInput(attrs={"class": 'form-control', 'placeholder': '请输入密码'}))
    confirm_password = forms.CharField(label="重复密码", widget=forms.PasswordInput(
        attrs={"class": 'form-control', 'placeholder': '请再次输入密码'}))
    code = forms.CharField(label="验证码",
                           widget=forms.TextInput(attrs={"class": 'form-control', 'placeholder': '请输入验证码'}))

    class Meta:
        model = models.UserInfo
        # 优先展示form中的字段，接着才展示modelform剩下的字段
        # fields = "__all__"
        # 重新定义页面中展示的顺序
        fields = ['mobile_phone', 'password', 'confirm_password', 'code']

    def clean_password(self):
        pwd = self.cleaned_data['password']
        # 加密密码
        pwd = encrypt.md5(pwd)
        return pwd

    def clean_confirm_password(self):
        pwd = self.cleaned_data.get('password')
        conform_pwd = self.cleaned_data['confirm_password']
        conform_pwd = encrypt.md5(conform_pwd)
        if pwd != conform_pwd:
            raise ValidationError('两次密码不一致')

        return conform_pwd

    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data['mobile_phone']

        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exists:
            return mobile_phone

        raise ValidationError('手机号不存在')

    def clean_code(self):
        code = self.cleaned_data['code']
        mobile_phone = self.cleaned_data['mobile_phone']

        conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)
        if not redis_code:
            raise ValidationError('验证码失效或未发送，请重新发送')

        redis_str_code = redis_code.decode('utf-8')

        if redis_str_code != code.strip():
            raise ValidationError('验证码错误，请重新输入')
        return code


class UserForm(forms.ModelForm):
    username = forms.CharField(label='用户名',
                               widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入用户名'}))
    password = forms.CharField(label="密码",
                               max_length=64,
                               error_messages={
                                   'max_length': '密码长度不能大于64个字符'
                               },
                               widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': '请输入密码'}))
    code = forms.CharField(label='图片验证码',
                           widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入图片验证码'}))

    class Meta:
        model = models.CustomerInfo
        # 优先展示form中的字段，接着才展示modelform剩下的字段
        fields = ['username', 'password','code']
    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_password(self):
        pwd = self.cleaned_data['password']
        return pwd

    def clean_code(self):
        """检验验证码是否正确"""
        code = self.cleaned_data['code']
        session_image_code = self.request.session.get('image_code')

        if not session_image_code:
            raise ValidationError('验证码已过期！请重新输入')

        if code.strip().upper() != session_image_code.strip().upper():
            raise ValidationError('验证码错误')

        return code
class UserRegisterForm(forms.ModelForm):
    username = forms.CharField(label='用户名',
                               widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入用户名'}))
    password = forms.CharField(label="密码",
                               max_length=64,
                               error_messages={
                                   'max_length': '密码长度不能大于64个字符'
                               },
                               widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': '请输入密码'}))
    confirm_password = forms.CharField(label="重复密码", widget=forms.PasswordInput(
        attrs={"class": 'form-control', 'placeholder': '请再次输入密码'}))
    code = forms.CharField(label='图片验证码',
                           widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入图片验证码'}))

    class Meta:
        model = models.CustomerInfo
        # 优先展示form中的字段，接着才展示modelform剩下的字段
        fields = ['username', 'password', 'confirm_password','code']
    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_password(self):
        pwd = self.cleaned_data['password']
        return pwd
    def clean_confirm_password(self):
        pwd = self.cleaned_data.get('password')
        conform_pwd = self.cleaned_data['confirm_password']
        if pwd != conform_pwd:
            raise ValidationError('两次密码不一致')

        return conform_pwd
    def clean_code(self):
        """检验验证码是否正确"""
        code = self.cleaned_data['code']
        session_image_code = self.request.session.get('image_code')

        if not session_image_code:
            raise ValidationError('验证码已过期！请重新输入')

        if code.strip().upper() != session_image_code.strip().upper():
            raise ValidationError('验证码错误')

        return code
class UserresetForm(forms.Form):
    username = forms.CharField(label='用户名',
                               widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入用户名'}))
    password = forms.CharField(label="密码",
                               max_length=64,
                               error_messages={
                                   'max_length': '密码长度不能大于64个字符'
                               },
                               widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': '请输入密码'}))
    confirm_password = forms.CharField(label="重复密码", widget=forms.PasswordInput(
        attrs={"class": 'form-control', 'placeholder': '请再次输入密码'}))
    code = forms.CharField(label="验证码",
                           widget=forms.TextInput(attrs={"class": 'form-control', 'placeholder': '请输入验证码'}))
    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_password(self):
        pwd = self.cleaned_data['password']
        return pwd
    def clean_confirm_password(self):
        pwd = self.cleaned_data.get('password')
        conform_pwd = self.cleaned_data['confirm_password']
        if pwd != conform_pwd:
            raise ValidationError('两次密码不一致')

        return conform_pwd

    def clean_code(self):
        """检验验证码是否正确"""
        code = self.cleaned_data['code']
        session_image_code = self.request.session.get('image_code')

        if not session_image_code:
            raise ValidationError('验证码已过期！请重新输入')

        if code.strip().upper() != session_image_code.strip().upper():
            raise ValidationError('验证码错误')

        return code